﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using MyBasicLib.Utilities.Log;
using MyBasicLib.Utilities;

namespace MyBasicLib.Data.ORMLiteNew
{ 
    /// <summary>
    /// 数据访问入口 
    /// </summary>
    public sealed class DataContext 
    { 
        /// <summary>
        /// 数据访问提供程序
        /// </summary>
        public IDbQueryProvider Provider { get; set; } 

        /// <summary>
        /// 用于延迟执行Insert,Delete,Update操作
        /// </summary>
        private readonly List<IDbQueryable> querys = new List<IDbQueryable>();

        #region 构造函数

        public DataContext()
            : this(IOC.DefaultContainer.Resolve<IDbQueryProvider>())
        {
        }
        public DataContext(IDbQueryProvider provider) 
        {
            CommandTimeout = 30;

            Provider = provider;
            //if (!string.IsNullOrEmpty(conn))
            //{
            //    var dbProvider = Provider as DbQueryProvider;
            //    if (dbProvider != null)
            //    {
            //        dbProvider.ConnectionString = conn;
            //    }
            //}
        }
        #endregion
 
        /// <summary>
        /// The time (in seconds) to wait for the command to execute. The default value   is 30 seconds.
        /// </summary>
        public int CommandTimeout { get; set; }

    
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">实体</param>
        public void Insert<T>(T value) where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            iq.DbExpressions.Add(new InsertDbExpression(value));

            lock (querys)
            {
                // sqls.Add(() => this.CreateCommand(iq));
                querys.Add(iq);
            }
        }
        /// <summary>
        /// 新增
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">实体列表</param>
        public void Insert<T>(IEnumerable<T> values) where T : ITable
        {
            foreach (T value in values)
            {
                Insert(value);
            }
        }
        /// <summary>
        /// 新增从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">查询</param>
        public void Insert<T>(IDbQueryable<T> query) where T : ITable
        {
            IDbQueryable<T> iq = query;
            iq.DbExpressions.Add(new InsertDbExpression() );

            lock (querys)
            { 
                querys.Add(iq);
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">条件</param>
        public void Delete<T>(Expression<Func<T, bool>> predicate) where T : ITable
        {
            Delete<T>(p => p.Where(predicate));
        }

        private void Delete<T>(Func<IDbQueryable<T>, IDbQueryable<T>> predicate) where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            IDbQueryable<T> newIq = predicate(iq);
            Delete(newIq);
        }
        /// <summary>
        /// 删除从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query">查询</param>
        public void Delete<T>(IDbQueryable<T> query) where T : ITable
        {
            query.DbExpressions.Add(new DeleteDbExpression());
            lock (querys)
            {
                //sqls.Add(() => this.CreateCommand(query));
                querys.Add(query);
            }
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="newValue">实体</param>
        public void Update<T>(T newValue) where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            iq.DbExpressions.Add(new UpdateDbExpression(newValue));
            lock (querys)
            {
                // sqls.Add(() => CreateCommand(iq));
                querys.Add(iq);
            }
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action">要更新的字段</param>
        /// <param name="predicate">条件</param>
        public void Update<T>(Expression<Func<T, T>> action, Expression<Func<T, bool>> predicate) where T : ITable
        {
            Update(action, p => p.Where(predicate));
        }

        private void Update<T>(Expression<Func<T, T>> action, Func<IDbQueryable<T>, IDbQueryable<T>> predicate)
            where T : ITable
        {
            IDbQueryable<T> iq = GetTable<T>();
            IDbQueryable<T> newIq = predicate(iq);
            Update(action, newIq);
        }
        /// <summary>
        /// 更新从查询里
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action">要更新的字段</param>
        /// <param name="query">查询</param>
        public void Update<T>(Expression<Func<T, T>> action, IDbQueryable<T> query) where T : ITable
        {
            query.DbExpressions.Add(new UpdateDbExpression(action));
            lock (querys)
            {
                //sqls.Add(() => CreateCommand(query));
                querys.Add(query);
            }
        }
        /// <summary>
        /// 提交事务
        /// </summary>
        /// <returns>影响记录数量</returns>
        public int SubmitChanges()
        {
            return Provider.SubmitChanges(querys);
        }
        /// <summary>
        /// 取消事务
        /// </summary>
        public void DiscardChanges()
        {
            lock (querys)
            {
                querys.Clear();
            }
        }
        /// <summary>
        /// 查询某个表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IDbQueryable<T> GetTable<T>() where T : ITable
        {
            return new DbQueryable<T>(Provider);
        }
       
    }
}